package com.bingxue.edu.management.education.service.exam;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.bingxue.edu.management.education.model.aggregate.ExamRecordAggregate;
import com.bingxue.edu.management.education.model.entity.exam.Exam;
import com.bingxue.edu.management.education.model.entity.exam.ExamAnswerRecord;
import com.bingxue.edu.management.education.model.entity.exam.ExamQuestion;
import com.bingxue.edu.management.education.model.entity.exam.ExamRecord;
import com.bingxue.edu.management.system.service.DictItemService;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author panbo
 * @since 2023/10/9
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ExamRecordDataListener extends AnalysisEventListener<Map<Integer, String>> {
    private static final int START_INDEX = 3;

    //表头数据
    private final Map<Integer, String> questionTypeMap = new HashMap<>();
    private final Map<Integer, Integer> questionSortMap = new HashMap<>();
    private final Map<Integer, String> questionModuleMap = new HashMap<>();
    private final Map<Integer, String> questionKPointsMap = new HashMap<>();
    private final Map<Integer, BigDecimal> questionScoreMap = new HashMap<>();
    private final List<Map<Integer, String>> examDataList = new LinkedList<>();

    @Getter
    private String examName;

    @Getter
    @Setter
    private Exam exam;


    private List<ExamQuestion> questionList = null;

    private final DictItemService dictItemService;

    /**
     * 解析表头
     * 逐行解析
     * @param headMap 将表头的每列的序号当作键,列上的值当作值自动注入到参数的headMap中
     * @param context 用来控制解析的行的上下文
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        log.debug("解析到一条head:{}", JSON.toJSONString(headMap));
        // 第一行，读取考试名称
        if (context.readRowHolder().getRowIndex().equals(0)) {
            resolveExam(headMap);
        } else if (context.readRowHolder().getRowIndex().equals(1)) {
            resolveQuestionType(headMap);
        } else if (context.readRowHolder().getRowIndex().equals(2)) {
            resolveQuestionSort(headMap);
        } else if (context.readRowHolder().getRowIndex().equals(3)) {
            resolveQuestionModule(headMap);
        } else if (context.readRowHolder().getRowIndex().equals(4)) {
            resolveQuestionKPoints(headMap);
        } else if (context.readRowHolder().getRowIndex().equals(5)) {
            resolveQuestionScore(headMap);
        }
    }

    /**
     * 解析数据行,将每行生成的map添加到examDataList中
     * 逐行解析
     * @param data 逐行解析生成的map集合,键为列序号,值为表单元格的值
     * @param context 上下文
     */
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        log.debug("解析到一条数据:{}", JSON.toJSONString(data));
        examDataList.add(data);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("解析完成");
    }

    /**
     * 获取考试记录聚合对象
     * 包含考试记录和考试回答记录和考题信息
     * @return
     */
    public List<ExamRecordAggregate> getExamRecordAggregateList() {
            List<ExamRecordAggregate> examRecordAggregates =new LinkedList<>();
            //一个map代表一个学生的成绩信息
            for (Map<Integer, String> data : examDataList) {
                ExamRecordAggregate examRecordAggregate = new ExamRecordAggregate();
                ExamRecord examRecord = new ExamRecord();
                examRecord.setExamId(exam.getId());
                List<ExamAnswerRecord> answerRecordList=new ArrayList<>();
                data.forEach((key, value) -> {
                    ExamAnswerRecord answerRecord = new ExamAnswerRecord();
//                    System.out.println("key: " + key + ", value: " + value);
                    if (key.equals(0)) {//提取班级id
                        examRecord.setClassId((value.trim()));
                    } else if (key.equals(1)) {//提取学生id
                        examRecord.setStudentId(value.trim());
                    } else if (key.equals(2)) {//提取总分,自定计算得
                        // 总分。忽略，自动计算
                    } else {
                        //学生的每题的分数
                        BigDecimal score = BigDecimal.valueOf(0.0);
                        if (StringUtils.isNotBlank(value)) {
                            score = new BigDecimal(value.trim());
                        }

                        answerRecord.setExamId(exam.getId());
                        answerRecord.setStudentId(examRecord.getStudentId());
                        //设置考题id
                        ExamQuestion examQuestion = questionList.get(key - START_INDEX);
                        ValidationUtils.throwIfNull(examQuestion,"考试问题不能为空");
                        ValidationUtils.throwIf(score.compareTo(BigDecimal.ZERO) < 0 || score.compareTo(examQuestion.getScore()) > 0, "分数必须大于0且小于题目总分");
                        answerRecord.setQuestionId(examQuestion.getId());

                        answerRecord.setExamRecordId(null);//将examRecord插入后再录入这个examRecordId
                        answerRecord.setCorrected(score.compareTo(questionScoreMap.get(key - START_INDEX)) == 0);
                        answerRecord.setScore(score);
                        answerRecordList.add(answerRecord);
                    }
                });

                examRecordAggregate.setAnswerRecordList(answerRecordList);//答题记录

                examRecord.setTotalScore(examRecordAggregate.computeTotalScore());
                examRecord.setRank(-1);
                examRecordAggregate.setExamRecord(examRecord);

                examRecordAggregates.add(examRecordAggregate);
            }

            return examRecordAggregates;
    }

    /**
     * 获取考题中的问题列表
     * @return
     */
    public List<ExamQuestion> getQuestionList() {
        questionList = new LinkedList<>();
        ValidationUtils.throwIfNull(exam, "考试数据为空");
        for (Integer key : questionTypeMap.keySet()) {
            ExamQuestion examQuestion = new ExamQuestion();
            examQuestion.setExamId(exam.getId());
            examQuestion.setQuestionType(questionTypeMap.get(key));
            examQuestion.setQuestionModule(questionModuleMap.get(key));
            examQuestion.setKnowledgePoints(questionKPointsMap.get(key));
            examQuestion.setQuestionIndex(questionSortMap.get(key));
            examQuestion.setScore(questionScoreMap.get(key));

            //设置每道题的平均分数
            examQuestion.setAverageScore(computeAverageScore(key));
            questionList.add(examQuestion);
        }

        return questionList;
    }

    /**
     * 计算单个题的平均分数
     * @param key 题目序号
     * @return 平均分数
     */
    private BigDecimal computeAverageScore(Integer key) {
        BigDecimal averageScore = BigDecimal.ZERO;
        for (Map<Integer, String> map:examDataList){
            averageScore = averageScore.add(new BigDecimal(map.get(key+START_INDEX) ==null? "0": map.get(key+START_INDEX)));
        }
        return averageScore.divide(BigDecimal.valueOf(examDataList.size()));
    }

    /**
     * 获取表头中的考试名称
     * @param headMap
     */
    private void resolveExam(Map<Integer, String> headMap) {
        examName = headMap.get(START_INDEX).trim();
        ValidationUtils.throwIfNull(examName, "考试名称不能为空");
    }

    /**
     * 获取表头中的题目类型
     * @param headMap
     */
    private void resolveQuestionType(Map<Integer, String> headMap) {
        String lastType = null;
        for (Integer key : headMap.keySet()) {
            if (key >= START_INDEX) {
                if (!StringUtils.isBlank(headMap.get(key))) {
                    lastType = dictItemService.getDictItemValueByLabel(headMap.get(key),"QuestionType");
                    ValidationUtils.throwIfNull(lastType, "无效的题目类型: " + headMap.get(key));
                }
                questionTypeMap.put(key - START_INDEX, lastType);
            }
        }
    }

    /**
     * 获取表头中的考题中的题目序号
     * @param headMap
     */
    private void resolveQuestionSort(Map<Integer, String> headMap) {
        for (Integer key : headMap.keySet()) {
            if (key >= START_INDEX) {
                int sort = Integer.parseInt(headMap.get(key));
                questionSortMap.put(key - START_INDEX, sort);
            }
        }
    }

    /**
     * 获取表头中的题目所属模块
     * @param headMap
     */
    private void resolveQuestionModule(Map<Integer, String> headMap) {
        String lastModule=null;
        for (Integer key : headMap.keySet()) {
            if (key >= START_INDEX) {
                if (!StringUtils.isBlank(headMap.get(key))) {
                    String moduleNameLabel  = headMap.get(key).trim();//获取表格中的题目所属模块
                    lastModule = dictItemService.getDictItemValueByLabel(moduleNameLabel,"QuestionModule");//匹配枚举中的题目所属模块
                    ValidationUtils.throwIfNull(lastModule,"无效的题目模块:{} " , headMap.get(key));
                }
                questionModuleMap.put(key - START_INDEX, lastModule);
            }
        }
    }

    /**
     * 获取表头中的题目的知识点信息
     * @param headMap
     */
    private void resolveQuestionKPoints(Map<Integer, String> headMap) {
        for (Integer key : headMap.keySet()) {
            if (key >= START_INDEX) {
                String kPoints = headMap.get(key)!=null?headMap.get(key).trim():" ";
                questionKPointsMap.put(key - START_INDEX, kPoints);
            }
        }
    }

    /**
     * 获取表头中的题目的分数
     * @param headMap
     */
    private void resolveQuestionScore(Map<Integer, String> headMap) {
        for (Integer key : headMap.keySet()) {
            if (key >= START_INDEX) {
                BigDecimal score = BigDecimal.valueOf(Long.parseLong(headMap.get(key).trim()));
                ValidationUtils.throwIf(score.compareTo(BigDecimal.valueOf(0)) < 0,"无效的题目分数:{} " ,headMap.get(key));
                questionScoreMap.put(key - START_INDEX, score);
            }
        }
    }
}



